package com.template.web.exception;

import com.template.web.utils.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({
            NoHandlerFoundException.class,
            HttpRequestMethodNotSupportedException.class,
            HttpMediaTypeNotSupportedException.class,
            MissingPathVariableException.class,
            MissingServletRequestParameterException.class,
            TypeMismatchException.class,
            HttpMessageNotReadableException.class,
            HttpMessageNotWritableException.class,
            HttpMediaTypeNotAcceptableException.class,
            ServletRequestBindingException.class,
            ConversionNotSupportedException.class,
            MissingServletRequestPartException.class,
            AsyncRequestTimeoutException.class
    })
    public ResponseEntity<JsonResult<String>> handlerException(MissingServletRequestParameterException exception) {
        log.error("请求异常", exception);
        return new ResponseEntity<>(JsonResult.failed("请求异常"), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = {IllegalArgumentException.class})
    public ResponseEntity<JsonResult<String>> handlerException(IllegalArgumentException exception) {
        log.error("参数格式异常", exception);
        return new ResponseEntity<>(JsonResult.failed("参数格式异常"), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResponseEntity<JsonResult<String>> handlerException(MethodArgumentNotValidException exception) {
        log.error("参数校验异常", exception);
        String message = StringUtils.collectionToCommaDelimitedString(
                exception.getBindingResult().getFieldErrors()
                        .stream()
                        .map(FieldError::getDefaultMessage)
                        .collect(Collectors.toList()));
        return new ResponseEntity<>(JsonResult.failed("参数校验异常：" + message), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = BindException.class)
    public ResponseEntity<JsonResult<String>> handlerException(BindException exception) {
        log.error("参数绑定异常", exception);
        return new ResponseEntity<>(JsonResult.failed("参数绑定异常"), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = {NullPointerException.class})
    public ResponseEntity<JsonResult<String>> handlerException(NullPointerException exception) {
        log.error("空指针异常", exception);
        return new ResponseEntity<>(JsonResult.failed("空指针异常"), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(UnauthorizedException.class)
    @ResponseBody
    public ResponseEntity<JsonResult<String>> UnauthorizedExceptionHandler(UnauthorizedException exception) {
        log.error("操作权限异常", exception);
        return new ResponseEntity<>(JsonResult.failed("操作权限异常"), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(UnauthenticatedException.class)
    @ResponseBody
    public ResponseEntity<JsonResult<String>> UnauthenticatedException(UnauthenticatedException exception) {
        log.error("令牌验证异常", exception);
        return new ResponseEntity<>(JsonResult.failed("令牌验证异常"), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(IncorrectCredentialsException.class)
    @ResponseBody
    public ResponseEntity<JsonResult<String>> IncorrectCredentialsException(IncorrectCredentialsException exception) {
        log.error("令牌失效异常", exception);
        return new ResponseEntity<>(JsonResult.failed("令牌失效异常"), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity<JsonResult<String>> handlerException(Exception exception) {
        log.error("系统异常，请联系管理员", exception);
        return new ResponseEntity<>(JsonResult.failed("系统异常，请联系管理员"), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
